using System;
using System.Collections.Generic;

namespace SmartSite.Frame
{
    public class LongField : Field<long>, IValueField<long>
    {
        const int MaxCount = 64;
        public long MaxValue
        {
            get => Count < 2 ? Count.LongMask() : (Count - 1).LongMask();
        }

        public long MinValue
        {
            /*
             * Count 小于 2 时, 无符号位, 所以做无符号数处理
             * Count - 1 是除去符号位
            */
            get => Count < 2 ? 0 : (Count - 1).LongInversedMask();
        }

        readonly ValueOperating<long> ValueOperating;

        public LongField(List<byte> buffer, BitUnit index, BitUnit count)
        : base(buffer, index, count)
        {
            CheckingCountOutRange(count, nameof(count));
            ValueOperating = CreateValueOperating();
        }

        public LongField(IBytesBuffer buffer, BitUnit index, BitUnit count)
        : base(buffer, index, count)
        {
            CheckingCountOutRange(count, nameof(count));
            ValueOperating = CreateValueOperating();
        }

        public LongField(IField field, BitUnit count)
        : base(field, count)
        {
            CheckingCountOutRange(count, nameof(count));
            ValueOperating = CreateValueOperating();
        }

        public LongField(IField field)
        : base(field, MaxCount)
        {
            ValueOperating = CreateValueOperating();
        }

        void CheckingCountOutRange(int count, string name)
        {
            if (count > MaxCount || count < 0)
                throw new ArgumentOutOfRangeException(name);
        }

        ValueOperating<long> CreateValueOperating()
        {
            return new ValueOperating<long>(
                BitsVariable,
                Count,
                () => 0L,
                (a) => (byte)a,
                (a, c) => a << c,
                (a, c) => a >> c,
                (a, b) => a + b
            );
        }

        public override long Value
        {
            get
            {
                ValueOperating.RestoreBits(out long result).RestoreSign(ref result);
                return result;
            }
            set
            {
                if (value < MinValue || value > MaxValue)
                    throw new ArgumentOutOfRangeException(nameof(value));

                ValueOperating.ToByteList(value, out List<byte> bits).CopyToBitsVariable(bits);
            }
        }
    }
}
